package com.huaxin.device.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huaxin.device.common.MyMetaObjectHandler;
import com.huaxin.device.dto.ResponseCode;
import com.huaxin.device.dto.ResponseResult;
import com.huaxin.device.dto.enums.DeviceStatus;
import com.huaxin.device.dto.request.AddDeviceInstanceReqDTO;
import com.huaxin.device.dto.request.QueryDeviceInstanceListReqDTO;
import com.huaxin.device.dto.request.UpdateDeviceInstanceReqDTO;
import com.huaxin.device.mapper.DeviceInstanceMapper;
import com.huaxin.device.mapping.DeviceInstanceMapping;
import com.huaxin.device.models.DeviceInstance;
import com.huaxin.device.service.DeviceInstanceService;
import com.huaxin.feignclient.fluoritecloud.FluoriteCloudClient;
import com.huaxin.feignclient.fluoritecloud.models.FluoriteGetTokenResponse;
import com.huaxin.feignclient.fluoritecloud.models.FluoriteLiveUrlResponse;
import com.huaxin.feignclient.fluoritecloud.models.FluoriteResponse;
import com.huaxin.hxenum.enums.DeviceType;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Service
@RequiredArgsConstructor
public class DeviceInstanceServiceImpl extends ServiceImpl<DeviceInstanceMapper, DeviceInstance> implements DeviceInstanceService {
    private final ApplicationContext applicationContext;
    private final CacheManager cacheManager;
    private final MyMetaObjectHandler myMetaObjectHandler;
    private final DeviceInstanceMapping deviceInstanceMapping;
    private final FluoriteCloudClient fluoriteCloudClient;

    @Value(value = "${fluoriteCloud.appKey}")
    private String appKey;

    @Value(value = "${fluoriteCloud.appSecret}")
    private String appSecret;

    /**
     * 添加设备实例
     *
     * @param in
     * @return
     */
    @Override
    public ResponseResult<String> addDeviceInstance(AddDeviceInstanceReqDTO in) {
        if (in == null) {
            return ResponseResult.parameterError(null, "参数错误");
        }
        if (StringUtils.isBlank(in.getSerialNumber())) {
            return ResponseResult.parameterError(null, "设备序列号不能为空");
        }
        if (StringUtils.isBlank(in.getDeviceName())) {
            return ResponseResult.parameterError(null, "设备名称不能为空");
        }
        if (StringUtils.isBlank(in.getModelId())) {
            return ResponseResult.parameterError(null, "型号ID不能为空");
        }
        if (StringUtils.isBlank(in.getModelCode())) {
            return ResponseResult.parameterError(null, "型号编码不能为空");
        }
        if (StringUtils.isBlank(in.getDeviceType())) {
            return ResponseResult.parameterError(null, "设备类型不能为空");
        }
        long count = this.count(new LambdaQueryWrapper<DeviceInstance>().eq(DeviceInstance::getSerialNumber, in.getSerialNumber()));
        if (count > 0) {
            return ResponseResult.failure(ResponseCode.BAD_REQUEST, "设备序列号已存在", null);
        }
        DeviceInstance deviceInstance = deviceInstanceMapping.toEntity(in);
        deviceInstance.setStatus(DeviceStatus.OFFLINE);
        deviceInstance.setBindStatus(0);
        if (this.save(deviceInstance)) {
            return ResponseResult.ok("添加设备实例成功！");
        } else {
            return ResponseResult.failure(ResponseCode.INTERNAL_SERVER_ERROR, "添加设备实例失败，请稍后再试！", null);
        }
    }

    /**
     * 删除设备实例
     *
     * @param id
     * @return
     */
    @Override
    public ResponseResult<String> deleteDeviceInstance(String id) {
        if (StringUtils.isBlank(id)) {
            return ResponseResult.parameterError(null, "设备实例ID不能为空");
        }
        if (this.removeById(id)) {
            return ResponseResult.ok("删除设备实例成功！");
        } else {
            return ResponseResult.failure(ResponseCode.INTERNAL_SERVER_ERROR, "删除设备实例失败，请稍后再试！", null);
        }
    }

    /**
     * 修改设备实例
     *
     * @param in
     * @return
     */
    @Override
    public ResponseResult<String> updateDeviceInstance(UpdateDeviceInstanceReqDTO in) {
        if (in == null) {
            return ResponseResult.parameterError(null, "参数错误");
        }
        if (StringUtils.isBlank(in.getId())) {
            return ResponseResult.parameterError(null, "设备实例ID不能为空");
        }
        DeviceInstance deviceInstance = this.getById(in.getId());
        deviceInstanceMapping.updateEntity(in, deviceInstance);
        if (this.updateById(deviceInstance)) {
            return ResponseResult.ok("修改设备实例成功！");
        } else {
            return ResponseResult.failure(ResponseCode.INTERNAL_SERVER_ERROR, "修改设备实例失败，请稍后再试！", null);
        }
    }

    /**
     * 查询设备实例
     *
     * @param id
     * @return
     */
    @Override
    public DeviceInstance queryDeviceInstance(String id) {
        if (StringUtils.isBlank(id)) {
            throw new RuntimeException("设备实例ID不能为空");
        }
        return this.getById(id);
    }

    //根据设备autoId查询设备实例
    @Override
    public DeviceInstance queryDeviceInstanceByAutoId(Long autoId) {
        if (autoId == null || autoId <= 0) {
            return null;
        }
        DeviceInstance deviceInstance = this.getOne(new LambdaQueryWrapper<DeviceInstance>().eq(DeviceInstance::getAutoId, autoId));
        return deviceInstance;
    }

    /**
     * 查询设备实例列表
     *
     * @param in
     * @return
     */
    @Override
    public ResponseResult<Page<DeviceInstance>> queryDeviceInstanceList(QueryDeviceInstanceListReqDTO in) {
        if (in == null) {
            return ResponseResult.parameterError(null, "参数错误");
        }
        Page<DeviceInstance> page = new Page<>(in.getPageNum(), in.getPageSize());
        LambdaQueryWrapper<DeviceInstance> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(in.getSerialNumber())) {
            queryWrapper.like(DeviceInstance::getSerialNumber, in.getSerialNumber());
        }
        if (StringUtils.isNotBlank(in.getDeviceName())) {
            queryWrapper.like(DeviceInstance::getDeviceName, in.getDeviceName());
        }
        if (StringUtils.isNotBlank(in.getModelId())) {
            queryWrapper.eq(DeviceInstance::getModelId, in.getModelId());
        }
        if (StringUtils.isNotBlank(in.getModelId())) {
            queryWrapper.like(DeviceInstance::getModelId, in.getModelId());
        }
        if (StringUtils.isNotBlank(in.getDeviceType())) {
            queryWrapper.eq(DeviceInstance::getDeviceType, DeviceType.of(in.getDeviceType()));
        }
        if (StringUtils.isNotBlank(in.getZoneId())) {
            queryWrapper.eq(DeviceInstance::getZoneId, in.getZoneId());
        }
        if (StringUtils.isNotBlank(in.getZoneName())) {
            queryWrapper.like(DeviceInstance::getZoneName, in.getZoneName());
        }
        if (StringUtils.isNotBlank(in.getStatus())) {
            queryWrapper.eq(DeviceInstance::getStatus, DeviceStatus.of(in.getStatus()));
        }
        if (StringUtils.isNotBlank(in.getFamilyId())) {
            queryWrapper.eq(DeviceInstance::getFamilyId, in.getFamilyId());
        }
        if (StringUtils.isNotBlank(in.getOrgId())) {
            queryWrapper.like(DeviceInstance::getOrgId, in.getOrgId());
        }
        if (in.getBindStatus() != null && in.getBindStatus() >= 0) {
            queryWrapper.eq(DeviceInstance::getBindStatus, in.getBindStatus());
        }
        Page<DeviceInstance> pageData = this.page(page, queryWrapper);
        return ResponseResult.ok(pageData);
    }

    /**
     * 根据设备sn查询设备实例
     *
     * @param sn 设备sn
     * @return 设备实例
     */
    @Override
    public ResponseResult<DeviceInstance> queryDeviceInstanceBySn(String sn) {
        if (StringUtils.isBlank(sn)) {
            return ResponseResult.parameterError(null, "设备sn不能为空");
        }
        LambdaQueryWrapper<DeviceInstance> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeviceInstance::getSerialNumber, sn);
        DeviceInstance deviceInstance = this.getOne(queryWrapper);
        return ResponseResult.ok(deviceInstance);
    }

    /**
     * 将设备与用户进行绑定
     *
     * @param sn         设备sn
     * @param customerId 用户ID
     * @param userType   用户类型 1-企业；2-家庭
     * @return 条码
     */
    @Override
    public ResponseResult<String> bindDevice(String sn, String customerId, Integer userType) {
        if (StringUtils.isBlank(sn)) {
            return ResponseResult.parameterError(null, "设备sn不能为空");
        }
        if (StringUtils.isBlank(customerId)) {
            return ResponseResult.parameterError(null, "用户ID不能为空");
        }
        if (userType == null || userType < 1 || userType > 2) {
            return ResponseResult.parameterError(null, "用户类型错误");
        }
        DeviceInstance deviceInstance = this.queryDeviceInstanceBySn(sn).getData();
        if (deviceInstance == null) {
            return ResponseResult.notFound(null, "设备不存在");
        }
        if (deviceInstance.getBindStatus() == 1) {
            return ResponseResult.failure(ResponseCode.INTERNAL_SERVER_ERROR, "该设备已绑定用户", null);
        }

        deviceInstance.setBindStatus(1);
        if (userType == 1) {
            deviceInstance.setOrgId(customerId);
        } else {
            deviceInstance.setFamilyId(customerId);
        }
        if (this.updateById(deviceInstance)) {
            return ResponseResult.ok("绑定成功！");
        } else {
            return ResponseResult.failure(ResponseCode.INTERNAL_SERVER_ERROR, "绑定失败，请稍后再试！", null);
        }
    }

    /**
     * 将设备与用户进行解绑
     *
     * @param sn 设备sn
     * @return 解绑结果
     */
    @Override
    public ResponseResult<String> unbindDevice(String sn) {
        if (StringUtils.isBlank(sn)) {
            return ResponseResult.parameterError(null, "设备sn不能为空");
        }
        DeviceInstance deviceInstance = this.queryDeviceInstanceBySn(sn).getData();
        if (deviceInstance == null) {
            return ResponseResult.notFound(null, "设备不存在");
        }
        deviceInstance.setBindStatus(0);
        deviceInstance.setOrgId("");
        deviceInstance.setFamilyId("");
        if (this.updateById(deviceInstance)) {
            return ResponseResult.ok("解绑成功！");
        } else {
            return ResponseResult.failure(ResponseCode.INTERNAL_SERVER_ERROR, "解绑失败，请稍后再试！", null);
        }
    }

    /**
     * 分页查询某客户绑定的设备列表
     *
     * @param customerId 客户ID
     * @return 设备列表
     */
    @Override
    public ResponseResult<Page<DeviceInstance>> queryDeviceInstanceListByCustomerId(Integer pageNum, Integer pageSize, String customerId) {
        Page<DeviceInstance> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<DeviceInstance> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isBlank(customerId)) {
            return ResponseResult.parameterError(null, "客户ID不能为空");
        }
        queryWrapper.and(queryWrapper1 -> queryWrapper1.eq(DeviceInstance::getFamilyId, customerId).or().eq(DeviceInstance::getOrgId, customerId))
                .eq(DeviceInstance::getBindStatus, 1);
        return ResponseResult.ok(this.page(page, queryWrapper));
    }

    /**
     * 分页查询区域下的设备列表
     *
     * @param zoneId 客户ID
     * @return 设备列表
     */
    @Override
    public ResponseResult<Page<DeviceInstance>> queryDeviceInstanceListByZoneId(Integer pageNum, Integer pageSize, String zoneId) {
        Page<DeviceInstance> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<DeviceInstance> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeviceInstance::getZoneId, zoneId)
                .eq(DeviceInstance::getBindStatus, 1);
        return ResponseResult.ok(this.page(page, queryWrapper));
    }

    /**
     * 获取视频播放地址
     *
     * @param serialNumber 设备序列号
     * @return 视频播放地址
     */
    @Override
    public ResponseResult<String> getVideoPlayUrl(String serialNumber) {
        Map<String, String> tokenParams = new HashMap<>();
        tokenParams.put("appKey", appKey);
        tokenParams.put("appSecret", appSecret);
        FluoriteResponse<FluoriteGetTokenResponse> token = fluoriteCloudClient.getToken(tokenParams);
        if (!Objects.equals(token.getCode(), "200")) {
            return ResponseResult.failure(ResponseCode.INTERNAL_SERVER_ERROR, token.getMsg(), null);
        }
        FluoriteGetTokenResponse tokenData = token.getData();
        Map<String, String> liveUrlParams = new HashMap<>();
        liveUrlParams.put("accessToken", tokenData.getAccessToken());
        liveUrlParams.put("deviceSerial", serialNumber);
        liveUrlParams.put("channelNo", "1");
        FluoriteResponse<FluoriteLiveUrlResponse> liveUrl = fluoriteCloudClient.getLiveUrl(liveUrlParams);
        if (!Objects.equals(liveUrl.getCode(), "200")) {
            return ResponseResult.failure(ResponseCode.INTERNAL_SERVER_ERROR, liveUrl.getMsg(), null);
        }
        FluoriteLiveUrlResponse liveUrlData = liveUrl.getData();
        return ResponseResult.ok(liveUrlData.getUrl());
    }
}
